home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / elv18src.zip / input.c < prev    next >
C/C++ Source or Header  |  1994-01-28  |  17KB  |  883 lines

  1. /* input.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains the input() function, which implements vi's INPUT mode.
  12.  * It also contains the code that supports digraphs.
  13.  */
  14.  
  15. #include "config.h"
  16. #include "ctype.h"
  17. #include "vi.h"
  18.  
  19.  
  20. #ifndef NO_DIGRAPH
  21. static struct _DIG
  22. {
  23.     struct _DIG    *next;
  24.     char        key1;
  25.     char        key2;
  26.     char        dig;
  27.     char        save;
  28. } *digs;
  29.  
  30. char digraph(key1, key2)
  31.     int    key1;    /* the underlying character */
  32.     int    key2;    /* the second character */
  33. {
  34.     int        newkey;
  35.     REG struct _DIG    *dp;
  36.  
  37.     /* if digraphs are disabled, then just return the new char */
  38.     if (!*o_digraph)
  39.     {
  40.         return key2;
  41.     }
  42.  
  43.     /* remember the new key, so we can return it if this isn't a digraph */
  44.     newkey = key2;
  45.  
  46.     /* sort key1 and key2, so that their original order won't matter */
  47.     if (key1 > key2)
  48.     {
  49.         key2 = key1;
  50.         key1 = newkey;
  51.     }
  52.  
  53.     /* scan through the digraph chart */
  54.     for (dp = digs;
  55.          dp && (dp->key1 != key1 || dp->key2 != key2);
  56.          dp = dp->next)
  57.     {
  58.     }
  59.  
  60.     /* if this combination isn't in there, just use the new key */
  61.     if (!dp)
  62.     {
  63.         return newkey;
  64.     }
  65.  
  66.     /* else use the digraph key */
  67.     return dp->dig;
  68. }
  69.  
  70. /* this function lists or defines digraphs */
  71. void do_digraph(bang, extra)
  72.     int    bang;
  73.     char    extra[];
  74. {
  75.     int        dig;
  76.     REG struct _DIG    *dp;
  77.     struct _DIG    *prev;
  78.     static int    user_defined = FALSE; /* boolean: are all later digraphs user-defined? */
  79.     char        listbuf[8];
  80.  
  81.     /* if "extra" is NULL, then we've reached the end of the built-ins */
  82.     if (!extra)
  83.     {
  84.         user_defined = TRUE;
  85.         return;
  86.     }
  87.  
  88.     /* if no args, then display the existing digraphs */
  89.     if (*extra < ' ')
  90.     {
  91.         listbuf[0] = listbuf[1] = listbuf[2] = listbuf[5] = ' ';
  92.         listbuf[7] = '\0';
  93.         for (dig = 0, dp = digs; dp; dp = dp->next)
  94.         {
  95.             if (dp->save || bang)
  96.             {
  97.                 dig += 7;
  98.                 if (dig >= COLS)
  99.                 {
  100.                     addch('\n');
  101.                     exrefresh();
  102.                     dig = 7;
  103.                 }
  104.                 listbuf[3] = dp->key1;
  105.                 listbuf[4] = dp->key2;
  106.                 listbuf[6] = dp->dig;
  107.                 qaddstr(listbuf);
  108.             }
  109.         }
  110.         addch('\n');
  111.         exrefresh();
  112.         return;
  113.     }
  114.  
  115.     /* make sure we have at least two characters */
  116.     if (!extra[1])
  117.     {
  118.         msg("Digraphs must be composed of two characters");
  119.         return;
  120.     }
  121.  
  122.     /* sort key1 and key2, so that their original order won't matter */
  123.     if (extra[0] > extra[1])
  124.     {
  125.         dig = extra[0];
  126.         extra[0] = extra[1];
  127.         extra[1] = dig;
  128.     }
  129.  
  130.     /* locate the new digraph character */
  131.     for (dig = 2; extra[dig] == ' ' || extra[dig] == '\t'; dig++)
  132.     {
  133.     }
  134.     dig = extra[dig];
  135.     if (!bang && dig)
  136.     {
  137.         dig |= 0x80;
  138.     }
  139.  
  140.     /* search for the digraph */
  141.     for (prev = (struct _DIG *)0, dp = digs;
  142.          dp && (dp->key1 != extra[0] || dp->key2 != extra[1]);
  143.          prev = dp, dp = dp->next)
  144.     {
  145.     }
  146.  
  147.     /* deleting the digraph? */
  148.     if (!dig)
  149.     {
  150.         if (!dp)
  151.         {
  152. #ifndef CRUNCH
  153.             msg("%c%c not a digraph", extra[0], extra[1]);
  154. #endif
  155.             return;
  156.         }
  157.         if (prev)
  158.             prev->next = dp->next;
  159.         else
  160.             digs = dp->next;
  161.         _free_(dp);
  162.         return;
  163.     }
  164.  
  165.     /* if necessary, create a new digraph struct for the new digraph */
  166.     if (dig && !dp)
  167.     {
  168.         dp = (struct _DIG *)malloc(sizeof *dp);
  169.         if (!dp)
  170.         {
  171.             msg("Out of space in the digraph table");
  172.             return;
  173.         }
  174.         if (prev)
  175.             prev->next = dp;
  176.         else
  177.             digs = dp;
  178.         dp->next = (struct _DIG *)0;
  179.     }
  180.  
  181.     /* assign it the new digraph value */
  182.     dp->key1 = extra[0];
  183.     dp->key2 = extra[1];
  184.     dp->dig = dig;
  185.     dp->save = user_defined;
  186. }
  187.  
  188. # ifndef NO_MKEXRC
  189. void savedigs(fd)
  190.     int        fd;
  191. {
  192.     static char    buf[] = "digraph! XX Y\n";
  193.     REG struct _DIG    *dp;
  194.  
  195.     for (dp = digs; dp; dp = dp->next)
  196.     {
  197.         if (dp->save)
  198.         {
  199.             buf[9] = dp->key1;
  200.             buf[10] = dp->key2;
  201.             buf[12] = dp->dig;
  202.             write(fd, buf, (unsigned)14);
  203.         }
  204.     }
  205. }
  206. # endif
  207. #endif
  208.  
  209.  
  210. /* This function allows the user to replace an existing (possibly zero-length)
  211.  * chunk of text with typed-in text.  It returns the MARK of the last character
  212.  * that the user typed in.
  213.  */
  214. MARK input(from, to, when, delta)
  215.     MARK    from;    /* where to start inserting text */
  216.     MARK    to;    /* extent of text to delete */
  217.     int    when;    /* either WHEN_VIINP or WHEN_VIREP */
  218.     int    delta;    /* 1 to take indent from lower line, -1 for upper, 0 for none */
  219. {
  220.     char    key[2];    /* key char followed by '\0' char */
  221.     char    *build;    /* used in building a newline+indent string */
  222.     char    *scan;    /* used while looking at the indent chars of a line */
  223.     MARK    m;    /* some place in the text */
  224. #ifndef NO_EXTENSIONS
  225.     int    quit = FALSE;    /* boolean: are we exiting after this? */
  226.     int    inchg;    /* boolean: have we done a "beforedo()" yet? */
  227. #endif
  228.  
  229. #ifdef DEBUG
  230.     /* if "from" and "to" are reversed, complain */
  231.     if (from > to)
  232.     {
  233.         msg("ERROR: input(%ld:%d, %ld:%d)",
  234.             markline(from), markidx(from),
  235.             markline(to), markidx(to));
  236.         return MARK_UNSET;
  237.     }
  238. #endif
  239.  
  240.     key[1] = 0;
  241.  
  242.     /* if we're replacing text with new text, save the old stuff */
  243.     /* (Alas, there is no easy way to save text for replace mode) */
  244.     if (from != to)
  245.     {
  246.         cut(from, to);
  247.     }
  248.  
  249.     /* if doing a dot command, then reuse the previous text */
  250.     if (doingdot)
  251.     {
  252.         ChangeText
  253.         {
  254.             /* delete the text that's there now */
  255.             if (from != to)
  256.             {
  257.                 delete(from, to);
  258.             }
  259.  
  260.             /* insert the previous text */
  261.             cutname('.');
  262.             cursor = paste(from, FALSE, TRUE) + 1L;
  263.         }
  264.     }
  265.     else /* interactive version */
  266.     {
  267.         /* assume that whoever called this already did a beforedo() */
  268. #ifndef NO_EXTENSIONS
  269.         inchg = TRUE;
  270. #endif
  271.  
  272.         /* if doing a change within the line... */
  273.         if (from != to && markline(from) == markline(to))
  274.         {
  275.             /* mark the end of the text with a "$" */
  276.             change(to - 1, to, "$");
  277.         }
  278.         else
  279.         {
  280.             /* delete the old text right off */
  281.             if (from != to)
  282.             {
  283.                 delete(from, to);
  284.             }
  285.             to = from;
  286.         }
  287.  
  288.         /* handle autoindent of the first line, maybe */
  289.         cursor = from;
  290.         m = cursor + MARK_AT_LINE(delta);
  291.         if (delta != 0 && *o_autoindent && markidx(m) == 0
  292.          && markline(m) >= 1L && markline(m) <= nlines)
  293.         {
  294.             /* Only autoindent blank lines. */
  295.             pfetch(markline(cursor));
  296.             if (plen == 0)
  297.             {
  298.                 /* Okay, we really want to autoindent */
  299.                 pfetch(markline(m));
  300.                 for (scan = ptext, build = tmpblk.c;
  301.                      *scan == ' ' || *scan == '\t';
  302.                      )
  303.                 {
  304.                     *build++ = *scan++;
  305.                 }
  306.                 if (build > tmpblk.c)
  307.                 {
  308.                     *build = '\0';
  309.                     add(cursor, tmpblk.c);
  310.                     cursor += (int)(build - tmpblk.c);
  311.                     if (cursor > to)
  312.                         to = cursor;
  313.                 }
  314.             }
  315.         }
  316.  
  317.         /* repeatedly add characters from the user */
  318.         for (;;)
  319.         {
  320.             /* Get a character */
  321.             redraw(cursor, TRUE);
  322. #ifdef DEBUG2
  323.             msg("cursor=%ld.%d, to=%ld.%d",
  324.                 markline(cursor), markidx(cursor),
  325.                 markline(to), markidx(to));
  326. #endif
  327. #ifndef NO_ABBR
  328.             pfetch(markline(cursor));
  329.             build = ptext;
  330.             if (pline == markline(from))
  331.                 build += markidx(from);
  332.             for (scan = ptext + markidx(cursor); --scan >= build && !isspace(*scan); )
  333.             {
  334.             }
  335.             scan++;
  336.             key[0] = getabkey(when, ptext, markidx(cursor));
  337. #else
  338.             key[0] = getkey(when);
  339. #endif
  340. #ifndef NO_VISIBLE
  341.             if (key[0] != ctrl('O') && V_from != MARK_UNSET)
  342.             {
  343.                 msg("Can't modify text during a selection");
  344.                 beep();
  345.                 continue;
  346.             }
  347. #endif
  348.  
  349. #ifndef NO_EXTENSIONS
  350.             if (key[0] == ctrl('O'))
  351.             {
  352.                 if (inchg)
  353.                 {
  354.                     if (cursor < to)
  355.                     {
  356.                         delete(cursor, to);
  357.                         redraw(cursor, TRUE);
  358.                     }
  359.                     afterdo();
  360.                     inchg = FALSE;
  361.                 }
  362.             }
  363.             else if (key[0] != ctrl('['))
  364.             {
  365.                 if (!inchg)
  366.                 {
  367.                     beforedo(FALSE);
  368.                     inchg = TRUE;
  369.                 }
  370.             }
  371. #endif
  372.  
  373. #ifndef CRUNCH
  374.             /* if wrapmargin is set & we're past the
  375.              * warpmargin, then change the last whitespace
  376.              * characters on line into a newline
  377.              */
  378.             if (*o_wrapmargin)
  379.             {
  380.                 pfetch(markline(cursor));
  381.                 if (!ptext[markidx(cursor)]
  382.                  && idx2col(cursor, ptext, TRUE) > COLS - (*o_wrapmargin & 0xff))
  383.                 {
  384.                     build = tmpblk.c;
  385.                     *build++ = '\n';
  386.                     if (*o_autoindent)
  387.                     {
  388.                         /* figure out indent for next line */
  389.                         for (scan = ptext; *scan == ' ' || *scan == '\t'; )
  390.                         {
  391.                             *build++ = *scan++;
  392.                         }
  393.                     }
  394.                     *build = '\0';
  395.  
  396.                     scan = ptext + plen;
  397.                     m = cursor & ~(BLKSIZE - 1);
  398.                     while (ptext < scan)
  399.                     {
  400.                         scan--;
  401.                         if (*scan != ' ' && *scan != '\t')
  402.                             continue;
  403.  
  404.                         /*break up line, and we do autoindent if needed*/
  405.                         change(m + (int)(scan - ptext), m + (int)(scan - ptext) + 1, tmpblk